/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace DaveSexton.Sandcastle
{
	public sealed class UrlMappingGroup
	{
		#region Public Properties
		public Uri BaseUri
		{
			get
			{
				return baseUri;
			}
		}

		public string TopicId
		{
			get
			{
				return topicId;
			}
		}

		public string Target
		{
			get
			{
				return target;
			}
		}

		public UrlMappingProvider Provider
		{
			get
			{
				return provider;
			}
		}

		public string File
		{
			get
			{
				return file;
			}
		}

		public string ProviderType
		{
			get
			{
				return providerType;
			}
		}

		public string ProviderAssembly
		{
			get
			{
				return providerAssembly;
			}
		}

		public int MappingCount
		{
			get
			{
				return mappings.Count;
			}
		}

		public bool Initialized
		{
			get
			{
				return initialized;
			}
		}

		public string Configuration
		{
			get
			{
				return configuration;
			}
		}
		#endregion

		#region Private / Protected
		private readonly Dictionary<string, Uri> mappings = new Dictionary<string, Uri>(128, StringComparer.OrdinalIgnoreCase);
		private readonly Uri baseUri;
		private readonly string topicId, target, configuration, file, providerType, providerAssembly;
		private readonly UrlMappingProvider provider;
		private bool initialized;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="UrlMappingGroup" /> class.
		/// </summary>
		/// <remarks>
		/// This constructor is also used to support custom provider editors.
		/// </remarks>
		internal UrlMappingGroup(Uri baseUri, string target, string topicId, string file, UrlMappingProvider provider, string providerType, string providerAssembly, string configuration)
		{
			this.baseUri = baseUri;
			this.target = target;
			this.topicId = topicId;
			this.file = file;
			this.provider = provider ?? XmlUrlMappingProvider.Instance;
			this.providerType = providerType;
			this.providerAssembly = providerAssembly;
			this.configuration = configuration;
		}
		#endregion

		#region Methods
		public static UrlMappingGroup CreateFrom(string currentDirectory, XmlReader configuration, Action<UrlMappingReference> loadMappingAction)
		{
			UrlMappingGroup group = CreateFrom(currentDirectory, configuration);
			group.Initialize(loadMappingAction);
			
			return group;
		}

		public static UrlMappingGroup CreateFrom(string currentDirectory, XmlReader configuration)
		{
			if (configuration == null)
				throw new ArgumentNullException("configuration");
			
			if (configuration.ReadToFollowing("mappings"))
			{
				string @base = configuration.GetAttribute("base");
				string target = configuration.GetAttribute("target");
				string topicId = configuration.GetAttribute("topic");
				string providerType = configuration.GetAttribute("type");
				string providerAssembly = configuration.GetAttribute("assembly");
				string file = configuration.GetAttribute("file");
				
				Uri baseUri = null;

				if (!string.IsNullOrEmpty(@base))
					Uri.TryCreate(@base, UriKind.RelativeOrAbsolute, out baseUri);

				UrlMappingProvider provider;

				if (!string.IsNullOrEmpty(file))
				{
					if (string.IsNullOrEmpty(providerType))
						provider = new FileUrlMappingProvider(currentDirectory, file);
					else
						provider = new FileUrlMappingProvider(currentDirectory, file, providerType, providerAssembly);
				}
				else if (!string.IsNullOrEmpty(providerType))
					provider = UrlMappingProvider.GetProvider(providerType, providerAssembly);
				else
					provider = XmlUrlMappingProvider.Instance;

				return new UrlMappingGroup(baseUri, target, topicId, file, provider, providerType, providerAssembly, configuration.ReadOuterXml());
			}

			throw new XmlException(Resources.Errors.InvalidMappingsElement);
		}

		public void Initialize(Action<UrlMappingReference> loadMappingAction)
		{
			if (initialized)
				throw new InvalidOperationException(Resources.Errors.UrlMappingsAlreadyInitialized);

			if (loadMappingAction == null)
				throw new ArgumentNullException("loadMappingAction");

			foreach (UrlMapping mapping in provider.GetMappings(this, configuration))
			{
				if (mapping.Id != null)
				{
					loadMappingAction(new UrlMappingReference(this, mapping));
					mappings.Add(mapping.Id, mapping.Href);
				}
			}

			initialized = true;
		}

		public Uri GetMapping(string id)
		{
			if (mappings.ContainsKey(id))
				return mappings[id];
			else
				return null;
		}

		public bool HasMapping(string id)
		{
			return mappings.ContainsKey(id);
		}
		#endregion
	}
}
